# -*- coding: utf8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.cvm.v20170312 import cvm_client, models

import json

# 设置一次请求最高的服务器数量，避免耗尽资金
MAX_NEW_CVM_COUNT = 100

IS_DEBUG = True

with open('config/config.json', 'r') as f:
    myConfig = json.load(f)

try:
    cred = credential.Credential(myConfig['SecretId'], myConfig['SecretKey'])
    client = cvm_client.CvmClient(cred, myConfig['Region'])

    # # 选择地区
    # ret_j = client.DescribeRegions(models.DescribeRegionsRequest()).to_json_string()
    # if IS_DEBUG:
    #     print("[DEBUG]", ret_j)
    # ret_o = json.loads(ret_j)
    # regions = ret_o['RegionSet']
    # print('[编号]', '名称', '可用性', sep='\t\t\t')
    # for i in range(len(regions)):
    #     print('[' + str(i) + ']', regions[i]['RegionName'], regions[i]['RegionState'], sep='\t\t\t')
    # select_str = input("请选择地区，输入编号:")
    # select_str = select_str.strip()
    # myRegion = regions[int(select_str)]['Region']
    # print("已选择", regions[int(select_str)]['RegionName'])
    # # 根据 region 重新创建 client
    # client = cvm_client.CvmClient(cred, myRegion)

    # 选择区域
    ret = client.DescribeZones(models.DescribeZonesRequest())
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    zones = ret.ZoneSet
    print('[编号]', '名称', '可用性', sep='\t\t\t')
    for i in range(len(zones)):
        print('[' + str(i) + ']', zones[i].ZoneName, zones[i].ZoneState, sep='\t\t\t')
    select_str = input("请选择区域，输入编号:")
    select_str = select_str.strip()
    myZone = zones[int(select_str)].Zone
    print("已选择", zones[int(select_str)].ZoneName)

    # 选择计费方式
    chargeTypes = [{'Charge': 'POSTPAID_BY_HOUR', 'ChargeName': '按小时后付费'}, {'Charge': 'SPOTPAID', 'ChargeName': '竞价付费'}]
    print('[编号]', '名称', sep='\t\t\t')
    for i in range(len(chargeTypes)):
        print('[' + str(i) + ']', chargeTypes[i]['ChargeName'], sep='\t\t\t')
    select_str = input("请选择计费方式，输入编号:")
    select_str = select_str.strip()
    myChargeType = chargeTypes[int(select_str)]['Charge']
    print("已选择", chargeTypes[int(select_str)]['ChargeName'], myChargeType)

    # 列出机型
    req = models.DescribeInstanceTypeConfigsRequest()
    respFilter = models.Filter()
    respFilter.Name = "zone"
    respFilter.Values = [myZone]
    req.Filters = [respFilter]
    ret = client.DescribeInstanceTypeConfigs(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    instanceTypes = ret.InstanceTypeConfigSet
    print('[编号]', '名称', 'GPU 数量', 'CPU Core 数量', '内存大小 (GB)', sep='\t\t\t')
    for i in range(len(instanceTypes)):
        print('[' + str(i) + ']', instanceTypes[i].InstanceType,
              instanceTypes[i].GPU,
              instanceTypes[i].CPU,
              instanceTypes[i].Memory,
              sep='\t\t\t')
    select_str = input("请选择机型，输入编号:")
    select_str = select_str.strip()
    myInstanceType = instanceTypes[int(select_str)].InstanceType
    print("已选择", instanceTypes[int(select_str)].InstanceType)

    # 设置网络
    # https://cloud.tencent.com/document/api/213/15753#InternetAccessible
    print('网络计费类型暂设置为：流量按小时后付费、公网带宽 10 Mbps、分配公网 IP')
    myInternetAccessible = models.InternetAccessible()
    myInternetAccessible.InternetChargeType = 'TRAFFIC_POSTPAID_BY_HOUR'
    myInternetAccessible.InternetMaxBandwidthOut = 10
    myInternetAccessible.PublicIpAssigned = True
    print('私有网络暂设置为：默认网络、不用作公网网关、无 IPv6。')
    myInstanceCount = 0
    myPrivateIpAddresses = []
    select_str = input('是否需要指定实例的私有 IPv4 地址？[y/n]')
    select_str = select_str.strip()
    if select_str == 'y':
        while True:
            assert (myInstanceCount <= MAX_NEW_CVM_COUNT)
            if myInstanceCount == MAX_NEW_CVM_COUNT:
                print('数目到达限制。')
                break
            ip_str = input('输入第 ' + str(myInstanceCount) + ' 个实例（从1开始）的私有 IP 地址。留空代表输入结束。')
            if ip_str == '':
                break
            myPrivateIpAddresses.append(ip_str)
            myInstanceCount += 1
            assert (myInstanceCount == len(myPrivateIpAddresses))
        print('将会创建', myInstanceCount, '个实例。')
    myVirtualPrivateCloud = models.VirtualPrivateCloud()
    myVirtualPrivateCloud.VpcId = "DEFAULT"
    myVirtualPrivateCloud.SubnetId = "DEFAULT"
    myVirtualPrivateCloud.AsVpcGateway = False
    myVirtualPrivateCloud.PrivateIpAddresses = myPrivateIpAddresses
    myVirtualPrivateCloud.Ipv6AddressCount = 0

    # 选择私有镜像
    req = models.DescribeImagesRequest()
    respFilter = models.Filter()
    respFilter.Name = "image-type"
    respFilter.Values = ["PRIVATE_IMAGE"]
    req.Filters = [respFilter]
    ret = client.DescribeImages(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    images = ret.ImageSet
    print('[编号]', '名称', '创建时间', '类型', sep='\t\t\t')
    for i in range(len(images)):
        print('[' + str(i) + ']', images[i].ImageName, images[i].CreatedTime, images[i].ImageType,
              sep='\t\t\t')
    select_str = input("请选择私有镜像，输入编号，如果镜像太多则只列出第一页:")
    select_str = select_str.strip()
    myImageId = images[int(select_str)].ImageId
    print("已选择", images[int(select_str)].ImageName)

    # 询价
    myPlacement = models.Placement()
    myPlacement.Zone = myZone

    req = models.InquiryPriceRunInstancesRequest()
    req.Placement = myPlacement
    req.ImageId = myImageId
    req.InstanceChargeType = myChargeType
    req.InstanceType = myInstanceType
    req.InternetAccessible = myInternetAccessible
    req.VirtualPrivateCloud = myVirtualPrivateCloud
    ret = client.InquiryPriceRunInstances(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    print('单个实例价格：', ret.Price.InstancePrice.UnitPrice, '元每',
          ret.Price.InstancePrice.ChargeUnit, '。带宽价格：', ret.Price.BandwidthPrice.UnitPrice, '元每',
          ret.Price.BandwidthPrice.ChargeUnit, '。')
    print('注意：此价格可能与实际存在较大偏差，尤其是竞价实例。可能不包含硬盘价格。')

    if myInstanceCount == 0:
        select_str = input("请输入创建的实例数目，1 到 " + str(MAX_NEW_CVM_COUNT) + " :")
        select_str = select_str.strip()
        myInstanceCount = int(select_str)
        if myInstanceCount <= 0 or myInstanceCount > MAX_NEW_CVM_COUNT:
            print('已取消创建实例。')
            exit(1)

    # 询价
    req.InstanceCount = myInstanceCount
    ret = client.InquiryPriceRunInstances(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    print(myInstanceCount, '个实例总价格：', ret.Price.InstancePrice.UnitPrice, '元每',
          ret.Price.InstancePrice.ChargeUnit, '。带宽总价格：', ret.Price.BandwidthPrice.UnitPrice, '元每',
          ret.Price.BandwidthPrice.ChargeUnit, '。')
    print('注意：此价格可能与实际存在较大偏差，尤其是竞价实例。可能不包含硬盘价格。')

    # 模拟创建实例
    assert (myInstanceCount <= MAX_NEW_CVM_COUNT)

    req = models.RunInstancesRequest()
    req.Placement = myPlacement
    req.ImageId = myImageId
    req.InstanceChargeType = myChargeType
    req.InstanceType = myInstanceType
    req.InternetAccessible = myInternetAccessible
    req.InstanceCount = myInstanceCount
    req.VirtualPrivateCloud = myVirtualPrivateCloud
    req.DryRun = True

    ret = client.RunInstances(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())

    select_str = input("请输入 Yes 以创建 " + str(myInstanceCount) + " 个 " + myChargeType + " 实例:")
    select_str = select_str.strip()
    if select_str != 'Yes':
        print('已取消创建实例。')
        exit(1)

    # 创建实例
    req.DryRun = False
    ret = client.RunInstances(req)
    if IS_DEBUG:
        print("[DEBUG]", ret.to_json_string())
    myInstances = ret.InstanceIdSet

    # 保存实例列表
    with open('config/instances.json', 'w') as f:
        json.dump(myInstances, f)

    print("创建成功。可通过其他脚本查看这些实例的 IP 地址。")


except TencentCloudSDKException as err:
    print(err)
    exit(1)

except Exception as e:
    import traceback

    print('traceback.format_exc():\n%s' % traceback.format_exc())
    exit(1)
